<?php

namespace Biz\Services\Site;

use Lumen\Logger\Logger;
use Illuminate\Http\Request;
use Biz\Models\Site\SiteHotel;
use Biz\Libraries\TranslationUtil;
use Illuminate\Support\Facades\DB;
use Biz\Models\Site\SiteHotelRoomType;
use Biz\Criteria\Site\SiteFilterCriterion;
use Biz\Criteria\Site\HotelFilterCriterion;
use Biz\Criteria\Site\LocaleFilterCriterion;
use Lumen\Core\Exceptions\BusinessException;
use Illuminate\Contracts\Pagination\Paginator;
use Biz\Constants\Site\SiteHotelRoomTypeConstants;
use Biz\Repositories\Site\SiteHotelRoomTypeRepository;

/**
 * SiteHotelRoomTypeService.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class SiteHotelRoomTypeService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * @var SiteHotelService
     */
    protected $hotelService;

    /**
     * RepositoryController constructor.
     *
     * @param SiteHotelRoomTypeRepository $repository
     * @param SiteHotelService            $hotelService
     */
    public function __construct(SiteHotelRoomTypeRepository $repository, SiteHotelService $hotelService)
    {
        $this->repository                = $repository;
        $this->hotelService              = $hotelService;
    }

    /**
     * 列表页.
     *
     * @param Request $request
     * @param string  $hotel_id
     *
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|mixed
     */
    public function index(Request $request, $hotel_id): Paginator
    {
        /** @var SiteHotel $hotel */
        $hotel    = $this->hotelService->findByUid($hotel_id);
        $pageSize = $request->get('page_size', 10);

        $results = $this->repository
            ->with(['translations'])
            ->setCacheLifetime(0)
            ->pushCriterion(new HotelFilterCriterion($hotel->id))
            //->pushCriterion(new LocaleFilterCriterion())
            ->paginate($pageSize);

        return $results;
    }

    /**
     * Find.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return SiteHotelRoomType
     */
    public function find(int $id): SiteHotelRoomType
    {
        $hotelRoomType = $this->repository->find($id);
        if (is_null($hotelRoomType)) {
            throw new BusinessException(trans('site/hotel/room-type.not_found'));
        }

        return $hotelRoomType;
    }

    /**
     * Find By uid.
     *
     * @param string $uid
     *
     * @throws BusinessException
     *
     * @return SiteHotelRoomType
     */
    public function findByUid(string $uid): SiteHotelRoomType
    {
        $id   = SiteHotelRoomType::decodeUid($uid);

        return $this->find($id);
    }

    /**
     * With find.
     *
     * @param int   $id
     * @param array $with
     *
     * @throws BusinessException
     *
     * @return SiteHotelRoomType
     */
    public function findWith(int $id, $with = []): SiteHotelRoomType
    {
        $hotelRoomType = $this->repository->with($with)->find($id);
        if (is_null($hotelRoomType)) {
            throw new BusinessException(trans('site/hotel/room-type.not_found'));
        }

        return $hotelRoomType;
    }

    /**
     * Find By Site Id.
     *
     * @param int $hotelRoomType_id
     *
     * @throws BusinessException
     *
     * @return bool
     */
    public function findBySiteId(int $hotelRoomType_id)
    {
        $hotelRoomType = $this->repository
            ->pushCriterion(new SiteFilterCriterion($hotelRoomType_id))
            ->findFirst();

        return $hotelRoomType;
    }

    /**
     * Check Room Type Belong To Hotel.
     *
     * @param SiteHotel         $hotel
     * @param SiteHotelRoomType $hotelRoomType
     *
     * @throws BusinessException
     */
    public function checkRoomTypeBelongToHotel(SiteHotel $hotel, SiteHotelRoomType $hotelRoomType): void
    {
        if ($hotel->id !== $hotelRoomType->hotel_id) {
            throw new BusinessException(trans('site/hotel/room-type.not_found'));
        }
    }

    /**
     * store.
     *
     * @param Request $request
     * @param string  $hotel_id
     *
     * @throws \Exception
     *
     * @return SiteHotelRoomType
     */
    public function store(Request $request, string $hotel_id): SiteHotelRoomType
    {
        $data = $request->all();
        /** @var SiteHotel $hotel */
        $hotel = $this->hotelService->findByUid($hotel_id);

        $data['hotel_id'] = $hotel->id;

        return $this->create($data);
    }

    /**
     * Create.
     *
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SiteHotelRoomType
     */
    public function create(array $data): SiteHotelRoomType
    {
        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 创建介绍
            $data['status'] = SiteHotelRoomTypeConstants::STATUS_NORMAL;

            $data = TranslationUtil::convertTranslationsData($data);

            $hotelRoomType   = $this->repository->create($data);
            if (! $hotelRoomType) {
                throw new BusinessException(trans('site/hotel/room-type.create_fail'));
            }
            // Load Translations
            $hotelRoomType->load('translations');

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $hotelRoomType;
    }

    /**
     * Detail.
     *
     * @param string $hotel_id
     * @param string $room_type_id
     *
     * @throws BusinessException
     *
     * @return SiteHotelRoomType
     */
    public function show(string $hotel_id, string $room_type_id): SiteHotelRoomType
    {
        /** @var SiteHotel $hotel */
        $hotel = $this->hotelService->findByUid($hotel_id);

        $id            = SiteHotelRoomType::decodeUid($room_type_id);
        $hotelRoomType = $this->findWith($id, ['translations']);

        $this->checkRoomTypeBelongToHotel($hotel, $hotelRoomType);

        return $hotelRoomType;
    }

    /**
     * Edit.
     *
     * @param string $hotel_id
     * @param string $room_type_id
     * @param array  $data
     *
     * @throws \Exception
     *
     * @return SiteHotelRoomType
     */
    public function edit(string $hotel_id, string $room_type_id, array $data): SiteHotelRoomType
    {
        $id               = SiteHotelRoomType::decodeUid($room_type_id);
        $data['hotel_id'] = $hotel_id;

        return $this->update($id, $data);
    }

    /**
     * Update.
     *
     * @param int   $id
     * @param array $data
     *
     * @throws \Exception
     *
     * @return SiteHotelRoomType
     */
    public function update(int $id, array $data): SiteHotelRoomType
    {
        $hotelRoomType = $this->find($id);

        /** @var SiteHotel $hotel */
        $hotel_id         = $data['hotel_id'];
        $hotel            = $this->hotelService->findByUid($hotel_id);
        $data['hotel_id'] = $hotel->id;

        $this->checkRoomTypeBelongToHotel($hotel, $hotelRoomType);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $data = TranslationUtil::convertTranslationsData($data);

            $hotelRoomType   = $this->repository->update($hotelRoomType, $data);
            if (! $hotelRoomType) {
                throw new BusinessException(trans('site/hotel/room-type.create_fail'));
            }

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $hotelRoomType;
    }

    /**
     * Remove.
     *
     * @param string $hotel_id
     * @param string $room_type_id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function remove(string $hotel_id, string $room_type_id): bool
    {
        $id   = SiteHotelRoomType::decodeUid($room_type_id);

        return $this->delete($hotel_id, $id);
    }

    /**
     * Delete.
     *
     * @param string $hotel_id
     * @param int    $room_type_id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(string $hotel_id, int $room_type_id): bool
    {
        /** @var SiteHotelRoomType $hotelRoomType */
        $hotelRoomType = $this->find($room_type_id);

        /** @var SiteHotel $hotel */
        $hotel            = $this->hotelService->findByUid($hotel_id);
        $data['hotel_id'] = $hotel->id;

        $this->checkRoomTypeBelongToHotel($hotel, $hotelRoomType);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $this->repository->delete($hotelRoomType);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return true;
    }
}
